package com.mvc.finance.web;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;

import org.extremecomponents.table.limit.Limit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import com.mvc.base.model.Company;
import com.mvc.base.model.Customer;
import com.mvc.base.model.Supplier;
import com.mvc.base.service.CompanyManager;
import com.mvc.base.service.CustomerManager;
import com.mvc.base.service.SupplierManager;
import com.mvc.business.model.Order;
import com.mvc.business.model.Purchase;
import com.mvc.business.service.OrderManager;
import com.mvc.business.service.PurchaseManager;
import com.mvc.business.service.SampleManager;
import com.mvc.finance.model.BankStatement;
import com.mvc.finance.model.CommercialInvoice;
import com.mvc.finance.model.Currency;
import com.mvc.finance.service.BankStatementManager;
import com.mvc.finance.service.CommercialInvoiceManager;
import com.mvc.finance.service.CurrencyManager;
import com.mvc.finance.service.ExpenseApplyManager;
import com.mvc.framework.model.Dictionary;
import com.mvc.framework.service.DictionaryFacade;
import com.mvc.framework.service.PageManager;
import com.mvc.framework.util.DateUtils;
import com.mvc.framework.util.PageSearch;
import com.mvc.framework.util.PageUtils;
import com.mvc.framework.web.PageController;

/**
 * 
 * @author snowpbx
 * @version V1.0 Create Time: 2012-11-29
 */
@Controller
@RequestMapping("finance")
public class FinanceController extends PageController<Order> {

	@Autowired
	private OrderManager	         orderManager;

	@Autowired
	private PurchaseManager	         purchaseManager;

	@Autowired
	private BankStatementManager	 bankStatementManager;

	@Autowired
	private CommercialInvoiceManager	commercialInvoiceManager;

	@Autowired
	private DictionaryFacade	     dictionaryFacade;

	@Autowired
	private CustomerManager	         customerManager;

	@Autowired
	private SupplierManager	         supplierManager;

	@Autowired
	private ExpenseApplyManager	     expenseApplyManager;

	@Autowired
	private SampleManager	         sampleManager;

	@Autowired
	private CurrencyManager	         currencyManager;

	@Autowired
	private CompanyManager	         companyManager;

	public static Integer getNextMonth() {
		Date date = new Date();
		return Integer.parseInt(DateUtils.getDateFormat(DateUtils.FORMAT_YYYYMM).format(DateUtils.getPreviousOrNextMonthsOfDate(date, 1)));
	}

	public static Integer getMonth(Date date) {
		return Integer.parseInt(DateUtils.getDateFormat(DateUtils.FORMAT_YYYYMM).format(date));
	}

	@RequestMapping("received")
	public String received(HttpServletRequest request) {
		List<CommercialInvoice> allPaid = commercialInvoiceManager.getPaid();
		List<Dictionary> currencies = dictionaryFacade.getDictionariesByDictionaryId(1006);
		for (Dictionary currency : currencies) {
			double total = 0D;
			for (CommercialInvoice order : allPaid) {
				if (order.getCurrency().equals(currency.getValue())) {
					total += order.getTotal();
				}
			}
			currency.setRemark(String.valueOf(total));
		}
		Object[][] objects = sumCustomer(allPaid, currencies);
		request.setAttribute("customerSum", objects);
		request.setAttribute("currencies", currencies);
		return "finance/received";
	}

	@RequestMapping("paid")
	public String paid(HttpServletRequest request) {
		List<BankStatement> allUnPays = bankStatementManager.getPaid();
		List<Dictionary> currencies = dictionaryFacade.getDictionariesByDictionaryId(1006);
		for (Dictionary currency : currencies) {
			double total = 0D;
			for (BankStatement order : allUnPays) {
				if (order.getCurrency().equals(currency.getValue())) {
					total += order.getTotal();
				}
			}
			currency.setRemark(String.valueOf(total));
		}
		Object[][] objects = sumSupplier(allUnPays, currencies);
		request.setAttribute("customerSum", objects);
		request.setAttribute("currencies", currencies);
		return "finance/paid";
	}

	@RequestMapping("receivable")
	public String receivable(HttpServletRequest request) {
		List<CommercialInvoice> allUnPays = commercialInvoiceManager.getUnPay();
		List<Dictionary> currencies = dictionaryFacade.getDictionariesByDictionaryId(1006);
		int currentMonth = DateUtils.getCurrentMonth();
		int nextMonth = getNextMonth();
		for (Dictionary currency : currencies) {
			double total = 0D;
			double current = 0D;
			double next = 0D;
			for (CommercialInvoice order : allUnPays) {
				if (order.getCurrency().equals(currency.getValue())) {
					total += order.getTotal();
					if (order.getPredictPayDate() != null) {
						int month = getMonth(order.getPredictPayDate());
						if (month <= currentMonth) {
							current += order.getTotal();
						} else if (month == nextMonth) {
							next += order.getTotal();
						}
					}
				}
			}
			currency.setRemark(String.valueOf(total));
			currency.setReserver1(String.valueOf(current));
			currency.setReserver2(String.valueOf(next));
		}
		Object[][] objects = sumCustomer(allUnPays, currencies);
		request.setAttribute("customerSum", objects);
		request.setAttribute("currencies", currencies);
		return "finance/receivable";
	}

	@RequestMapping("supplierReceivable")
	public String supplierReceivable(HttpServletRequest request) {
		if (request.getSession().getAttribute("supplierId") != null) {
			Integer supplierId = (Integer) request.getSession().getAttribute("supplierId");
			return receivableBySupplier(request, supplierId, true);
		} else {
			request.setAttribute("suppliers", supplierManager.getAll());
		}
		return "finance/supplierReceivable";
	}

	@RequestMapping("supplierReceivable/{supplierId}")
	protected String receivableBySupplier(HttpServletRequest request, @PathVariable Integer supplierId, boolean self) {
		if (!self) {
			request.setAttribute("suppliers", supplierManager.getAll());
			request.setAttribute("supplierId", supplierId);
		}
		List<Purchase> allUnPays = purchaseManager.getUnPayPurchases(supplierId);
		List<Dictionary> currencies = dictionaryFacade.getDictionariesByDictionaryId(1006);
		int currentMonth = DateUtils.getCurrentMonth();
		int nextMonth = getNextMonth();
		for (Dictionary currency : currencies) {
			double total = 0D;
			double current = 0D;
			double next = 0D;
			for (Purchase order : allUnPays) {
				if (order.getCurrency().equals(currency.getValue())) {
					total += order.getTotal();
					if (order.getPredictPayDate() != null) {
						int month = getMonth(order.getPredictPayDate());
						if (month <= currentMonth) {
							current += order.getTotal();
						} else if (month == nextMonth) {
							next += order.getTotal();
						}
					}
				}
			}
			currency.setRemark(String.valueOf(total));
			currency.setReserver1(String.valueOf(current));
			currency.setReserver2(String.valueOf(next));
		}
		request.setAttribute("currencies", currencies);
		return "finance/supplierReceivable";
	}

	protected Object[][] sumSupplier(List<BankStatement> allUnPays, List<Dictionary> currencies) {
		Map<Integer, double[]> customerSum = new TreeMap<Integer, double[]>();
		int currencyCount = currencies.size();
		for (BankStatement order : allUnPays) {
			double[] sum = customerSum.get(order.getSupplierId());
			if (sum == null) {
				sum = new double[currencyCount];
			}
			sum[order.getCurrency() - 1] = sum[order.getCurrency() - 1] + order.getTotal();
			customerSum.put(order.getSupplierId(), sum);
		}
		Object[][] objects = new Object[customerSum.size()][2];
		int index = 0;
		List<Supplier> suppliers = supplierManager.getAll();
		for (Integer customerId : customerSum.keySet()) {
			for (Supplier customer : suppliers) {
				if (customer.getObjectId().equals(customerId)) {
					objects[index][0] = customer;
					objects[index][1] = customerSum.get(customerId);
					break;
				}
			}
			index++;
		}
		return objects;
	}

	@RequestMapping("dues")
	public String dues(HttpServletRequest request) {
		List<BankStatement> allUnPays = bankStatementManager.getUnPay();
		List<Dictionary> currencies = dictionaryFacade.getDictionariesByDictionaryId(1006);
		int currentMonth = DateUtils.getCurrentMonth();
		int nextMonth = getNextMonth();
		for (Dictionary currency : currencies) {
			double total = 0D;
			double current = 0D;
			double next = 0D;
			for (BankStatement order : allUnPays) {
				if (order.getCurrency().equals(currency.getValue())) {
					total += order.getTotal();
					if (order.getPredictPayDate() != null) {
						int month = getMonth(order.getPredictPayDate());
						if (month <= currentMonth) {
							current += order.getTotal();
						} else if (month == nextMonth) {
							next += order.getTotal();
						}
					}
				}
			}
			currency.setRemark(String.valueOf(total));
			currency.setReserver1(String.valueOf(current));
			currency.setReserver2(String.valueOf(next));
		}
		Object[][] objects = sumSupplier(allUnPays, currencies);
		request.setAttribute("customerSum", objects);
		request.setAttribute("currencies", currencies);
		return "finance/dues";
	}

	protected Object[][] sumCustomer(List<CommercialInvoice> allUnPays, List<Dictionary> currencies) {
		Map<Integer, double[]> customerSum = new TreeMap<Integer, double[]>();
		int currencyCount = currencies.size();
		for (CommercialInvoice order : allUnPays) {
			double[] sum = customerSum.get(order.getCustomerId());
			if (sum == null) {
				sum = new double[currencyCount];
			}
			sum[order.getCurrency() - 1] = sum[order.getCurrency() - 1] + order.getTotal();
			customerSum.put(order.getCustomerId(), sum);
		}
		Object[][] objects = new Object[customerSum.size()][2];
		int index = 0;
		List<Customer> customers = customerManager.getAll();
		for (Integer customerId : customerSum.keySet()) {
			for (Customer customer : customers) {
				if (customer.getObjectId().equals(customerId)) {
					objects[index][0] = customer;
					objects[index][1] = customerSum.get(customerId);
					break;
				}
			}
			index++;
		}
		return objects;
	}

	@RequestMapping("orderSummary")
	public String orderSummary(HttpServletRequest request) {
		List<Order> orders = orderManager.getAllOrder();
		List<Dictionary> currencies = dictionaryFacade.getDictionariesByDictionaryId(1006);
		int paiedCount = 0;
		for (Dictionary currency : currencies) {
			double total = 0D;
			double paied = 0D;
			double unpay = 0D;
			for (Order order : orders) {
				if (order.getCurrency().equals(currency.getValue())) {
					total += order.getTotal();
					if (order.getFinanceStatus() == Order.ORDER_FINANCE_STATUS_PAYED) {
						paiedCount++;
						paied += order.getTotal();
					} else {
						unpay += order.getTotal();
					}
				}
			}
			currency.setRemark(String.valueOf(total));
			currency.setReserver1(String.valueOf(paied));
			currency.setReserver2(String.valueOf(unpay));
		}
		List<Order> paiedOrder = new ArrayList<Order>();
		List<Order> unPaiedOrder = new ArrayList<Order>();
		for (Order order : orders) {
			if (order.getFinanceStatus() == Order.ORDER_FINANCE_STATUS_PAYED) {
				paiedOrder.add(order);
			} else {
				unPaiedOrder.add(order);
			}
		}
		Object[][] customerSum = sumOrderCustomer(paiedOrder, currencies);
		Object[][] customerSum2 = sumOrderCustomer(unPaiedOrder, currencies);
		request.setAttribute("customerSum", customerSum);
		request.setAttribute("currencies", currencies);
		request.setAttribute("orderCount", orders.size());
		request.setAttribute("paiedCount", paiedCount);
		request.setAttribute("customerSum2", customerSum2);
		return "finance/orderSummary";
	}

	protected Object[][] sumOrderCustomer(List<Order> allUnPays, List<Dictionary> currencies) {
		Map<Integer, double[]> customerSum = new TreeMap<Integer, double[]>();
		int currencyCount = currencies.size();
		for (Order order : allUnPays) {
			double[] sum = customerSum.get(order.getCustomerId());
			if (sum == null) {
				sum = new double[currencyCount];
			}
			sum[order.getCurrency() - 1] = sum[order.getCurrency() - 1] + order.getTotal();
			customerSum.put(order.getCustomerId(), sum);
		}
		Object[][] objects = new Object[customerSum.size()][2];
		int index = 0;
		List<Customer> customers = customerManager.getAll();
		for (Integer customerId : customerSum.keySet()) {
			for (Customer customer : customers) {
				if (customer.getObjectId().equals(customerId)) {
					objects[index][0] = customer;
					objects[index][1] = customerSum.get(customerId);
					break;
				}
			}
			index++;
		}
		return objects;
	}

	@RequestMapping("purchaseSummary")
	public String purchaseSummary(HttpServletRequest request) {
		List<Purchase> orders = purchaseManager.getAllPurchase();
		List<Dictionary> currencies = dictionaryFacade.getDictionariesByDictionaryId(1006);
		int paiedCount = 0;
		for (Dictionary currency : currencies) {
			double total = 0D;
			double paied = 0D;
			double unpay = 0D;
			for (Purchase order : orders) {
				if (order.getCurrency().equals(currency.getValue())) {
					total += order.getTotal();
					if (order.getFinanceStatus() == Order.ORDER_FINANCE_STATUS_PAYED) {
						paiedCount++;
						paied += order.getTotal();
					} else {
						unpay += order.getTotal();
					}
				}
			}
			currency.setRemark(String.valueOf(total));
			currency.setReserver1(String.valueOf(paied));
			currency.setReserver2(String.valueOf(unpay));
		}
		List<Purchase> paiedOrder = new ArrayList<Purchase>();
		List<Purchase> unPaiedOrder = new ArrayList<Purchase>();
		for (Purchase order : orders) {
			if (order.getFinanceStatus() == Order.ORDER_FINANCE_STATUS_PAYED) {
				paiedOrder.add(order);
			} else {
				unPaiedOrder.add(order);
			}
		}
		Object[][] customerSum = sumPurchaseSupplier(paiedOrder, currencies);
		Object[][] customerSum2 = sumPurchaseSupplier(unPaiedOrder, currencies);
		request.setAttribute("customerSum", customerSum);
		request.setAttribute("currencies", currencies);
		request.setAttribute("orderCount", orders.size());
		request.setAttribute("paiedCount", paiedCount);
		request.setAttribute("customerSum2", customerSum2);
		return "finance/purchaseSummary";
	}

	protected Object[][] sumPurchaseSupplier(List<Purchase> allUnPays, List<Dictionary> currencies) {
		Map<Integer, double[]> customerSum = new TreeMap<Integer, double[]>();
		int currencyCount = currencies.size();
		for (Purchase order : allUnPays) {
			double[] sum = customerSum.get(order.getSupplierId());
			if (sum == null) {
				sum = new double[currencyCount];
			}
			sum[order.getCurrency() - 1] = sum[order.getCurrency() - 1] + order.getTotal();
			customerSum.put(order.getSupplierId(), sum);
		}
		Object[][] objects = new Object[customerSum.size()][2];
		int index = 0;
		List<Supplier> suppliers = supplierManager.getAll();
		for (Integer customerId : customerSum.keySet()) {
			for (Supplier customer : suppliers) {
				if (customer.getObjectId().equals(customerId)) {
					objects[index][0] = customer;
					objects[index][1] = customerSum.get(customerId);
					break;
				}
			}
			index++;
		}
		return objects;
	}

	@RequestMapping("summarySale")
	public String summarySale(HttpServletRequest request, Integer companyId) {
		Limit limit = PageUtils.getLimit(request);
		PageSearch pageSearch = preparePage(request, limit);
		Date beginDate = null;
		if (pageSearch.getFilterValue("GED_beginDate") != null) {
			beginDate = (Date) pageSearch.getFilterValue("GED_beginDate");
		} else {
			beginDate = DateUtils.getBeginOfThePreviousOrNextMonths(-2);
		}
		Date endDate = null;
		if (pageSearch.getFilterValue("LED_endDate") != null) {
			endDate = (Date) pageSearch.getFilterValue("LED_endDate");
		} else {
			endDate = new Date();
		}
		List<Company> companies = companyManager.getAll();
		if (companyId == null) {
			companyId = companies.get(0).getObjectId();
		}
		request.setAttribute("companies", companies);
		request.setAttribute("companyId", companyId);
		List<Currency> rates = currencyManager.getAll();

		List<Object[]> bankStatement = purchaseManager.summary(companyId, beginDate, endDate);
		List<Object[]> commercialInvoice = orderManager.summary(companyId, beginDate, endDate);
		Object[] expenseApply = expenseApplyManager.summary(companyId, beginDate, endDate).get(0);

		List<Object[]> carrier = sampleManager.summary(companyId, beginDate, endDate);
		List<Dictionary> currencies = dictionaryFacade.getDictionariesByDictionaryId(1006);
		long orderCount = (Long) (orderManager.getCount(companyId, beginDate, endDate).get(0));
		long purchaseCount = (Long) (purchaseManager.getCount(companyId, beginDate, endDate).get(0));
		long expenceCount = (Long) (expenseApplyManager.getCount(companyId, beginDate, endDate).get(0))
		        + (Long) (sampleManager.getCount(companyId, beginDate, endDate).get(0));
		List<Order> datas = new ArrayList<Order>(currencies.size());
		double total = 0D;
		double totalSale = 0D;
		double totalPurchase = 0D;
		double totalExpense = 0D;
		for (Dictionary currency : currencies) {
			Order data = new Order();
			data.setRemark(currency.getName());
			data.setCurrency(currency.getValue());
			data.setSalesCondition("0");
			for (Object[] objects : commercialInvoice) {
				if (((Integer) objects[0]).equals(currency.getValue())) {
					data.setSalesCondition(String.valueOf(objects[1]));
					break;
				}
			}
			data.setShipment("0");
			for (Object[] objects : bankStatement) {
				if (((Integer) objects[0]).equals(currency.getValue())) {
					data.setShipment(String.valueOf(objects[1]));
					break;
				}
			}
			data.setPayment("0");
			if (currency.getValue() == 1) {
				data.setPayment(String.valueOf(expenseApply[1] == null ? 0 : expenseApply[1]));
			}
			data.setClientPo("0");
			for (Object[] objects : carrier) {
				if (((Integer) objects[0]).equals(currency.getValue())) {
					data.setClientPo(String.valueOf(objects[1]));
					break;
				}
			}
			Double rate = 1D;
			for (Currency temp : rates) {
				if (temp.getId().equals(currency.getValue())) {
					rate = temp.getRate();
					break;
				}
			}
			data.setQuantity(rate);
			data.setTotal((toDouble(data.getSalesCondition()) - toDouble(data.getShipment()) - toDouble(data.getPayment()) - toDouble(data
			        .getClientPo())) * rate);
			total += data.getTotal();
			totalSale += toDouble(data.getSalesCondition()) * rate;
			totalPurchase += toDouble(data.getShipment()) * rate;
			totalExpense += (toDouble(data.getPayment()) + toDouble(data.getClientPo())) * rate;
			datas.add(data);
		}
		request.setAttribute("datas", datas);
		request.setAttribute("orderCount", orderCount);
		request.setAttribute("purchaseCount", purchaseCount);
		request.setAttribute("expenceCount", expenceCount);
		request.setAttribute("totalSale", totalSale);
		request.setAttribute("totalPurchase", totalPurchase);
		request.setAttribute("totalExpense", totalExpense);
		request.setAttribute("total", total);
		request.setAttribute("search_GED_beginDate", beginDate);
		request.setAttribute("search_LED_endDate", endDate);
		return "finance/summarySale";
	}

	private static double toDouble(String str) {
		double result = 0D;
		try {
			result = Double.parseDouble(str);
		} catch (Exception e) {
		}
		return result;
	}

	@RequestMapping("summaryFinance")
	public String summaryFinance(HttpServletRequest request, Integer companyId) {
		Limit limit = PageUtils.getLimit(request);
		PageSearch pageSearch = preparePage(request, limit);
		Date beginDate = null;
		if (pageSearch.getFilterValue("GED_beginDate") != null) {
			beginDate = (Date) pageSearch.getFilterValue("GED_beginDate");
		} else {
			beginDate = DateUtils.getBeginOfThePreviousOrNextMonths(-2);
		}
		Date endDate = null;
		if (pageSearch.getFilterValue("LED_endDate") != null) {
			endDate = (Date) pageSearch.getFilterValue("LED_endDate");
		} else {
			endDate = new Date();
		}
		List<Company> companies = companyManager.getAll();
		if (companyId == null) {
			companyId = companies.get(0).getObjectId();
		}
		request.setAttribute("companies", companies);
		request.setAttribute("companyId", companyId);
		List<Currency> rates = currencyManager.getAll();

		List<Object[]> bankStatement = bankStatementManager.summary(companyId, beginDate, endDate);
		List<Object[]> commercialInvoice = commercialInvoiceManager.summary(companyId, beginDate, endDate);
		Object[] expenseApply = expenseApplyManager.summary(companyId, beginDate, endDate).get(0);

		List<Object[]> carrier = sampleManager.summary(companyId, beginDate, endDate);
		List<Dictionary> currencies = dictionaryFacade.getDictionariesByDictionaryId(1006);
		long orderCount = (Long) (orderManager.getCount(companyId, beginDate, endDate).get(0));
		long purchaseCount = (Long) (purchaseManager.getCount(companyId, beginDate, endDate).get(0));
		long expenceCount = (Long) (expenseApplyManager.getCount(companyId, beginDate, endDate).get(0))
		        + (Long) (sampleManager.getCount(companyId, beginDate, endDate).get(0));
		List<Order> datas = new ArrayList<Order>(currencies.size());
		double total = 0D;
		double totalSale = 0D;
		double totalPurchase = 0D;
		double totalExpense = 0D;
		for (Dictionary currency : currencies) {
			Order data = new Order();
			data.setRemark(currency.getName());
			data.setCurrency(currency.getValue());
			data.setSalesCondition("0");
			for (Object[] objects : commercialInvoice) {
				if (((Integer) objects[0]).equals(currency.getValue())) {
					data.setSalesCondition(String.valueOf(objects[1]));
					break;
				}
			}
			data.setShipment("0");
			for (Object[] objects : bankStatement) {
				if (((Integer) objects[0]).equals(currency.getValue())) {
					data.setShipment(String.valueOf(objects[1]));
					break;
				}
			}
			data.setPayment("0");
			if (currency.getValue() == 1) {
				data.setPayment(String.valueOf(expenseApply[1] == null ? 0 : expenseApply[1]));
			}
			data.setClientPo("0");
			for (Object[] objects : carrier) {
				if (((Integer) objects[0]).equals(currency.getValue())) {
					data.setClientPo(String.valueOf(objects[1]));
					break;
				}
			}
			Double rate = 1D;
			for (Currency temp : rates) {
				if (temp.getId().equals(currency.getValue())) {
					rate = temp.getRate();
					break;
				}
			}
			data.setQuantity(rate);
			data.setTotal((toDouble(data.getSalesCondition()) - toDouble(data.getShipment()) - toDouble(data.getPayment()) - toDouble(data
			        .getClientPo())) * rate);
			total += data.getTotal();
			totalSale += toDouble(data.getSalesCondition()) * rate;
			totalPurchase += toDouble(data.getShipment()) * rate;
			totalExpense += (toDouble(data.getPayment()) + toDouble(data.getClientPo())) * rate;
			datas.add(data);
		}
		request.setAttribute("datas", datas);
		request.setAttribute("orderCount", orderCount);
		request.setAttribute("purchaseCount", purchaseCount);
		request.setAttribute("expenceCount", expenceCount);
		request.setAttribute("totalSale", totalSale);
		request.setAttribute("totalPurchase", totalPurchase);
		request.setAttribute("totalExpense", totalExpense);
		request.setAttribute("total", total);
		request.setAttribute("search_GED_beginDate", beginDate);
		request.setAttribute("search_LED_endDate", endDate);
		return "finance/summaryFinance";
	}

	@Override
	public PageManager<Order> getEntityManager() {
		return null;
	}

	@Override
	public String getFileBasePath() {
		return null;
	}
}
